﻿using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using Red.Controls;

namespace Red.Controls
{
    /// <summary>
    /// A text box with buttons to the right
    /// </summary>
    /// <remarks>
    /// You should be able to use this control in an identical fashion to a standard text box control
    /// </remarks>
    [ContentProperty( "Controls" )]
    public partial class ButtonTextbox : UserControl
    {
        #region Public Properties

        #region Dependency Properties
        
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof( string ), typeof( ButtonTextbox ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
        public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( ButtonTextbox ) );

        #endregion Dependency Properties
        
        /// <summary>
        /// The text contained in the text box control
        /// </summary>
        public string Text
        {
            get { return (string)GetValue( TextProperty ); }
            set { SetValue( TextProperty, value ); }
        }

        /// <summary>
        /// Set the text box to read only
        /// </summary>
        public bool IsReadOnly
        {
            get { return (bool)GetValue( IsReadOnlyProperty ); }
            set { SetValue( IsReadOnlyProperty, value ); }
        }

        /// <summary>
        /// Every control that will be displayed to the right of the textbox
        /// </summary>
        public ObservableCollection<object> Controls { get; set; } = new ObservableCollection<object>();

        #endregion Public Properties

        #region C-Tor

        public ButtonTextbox()
        {
            InitializeComponent();

            Controls.CollectionChanged += Controls_CollectionChanged;
        }

        #endregion C-Tor

        #region Public Methods

        public void SelectAll() => _textBox.SelectAll();

        #endregion Public Methods

        #region Event Handlers

        private void Controls_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
        {
            if ( e.Action == NotifyCollectionChangedAction.Add )
            {
                foreach ( object o in e.NewItems )
                {
                    // Configure the buttons created from descriptions
                    ItemDescription.Button desc = o as ItemDescription.Button;

                    if ( desc != null )
                    {
                        desc.TextBox = _textBox;

                        continue;
                    }

                    // Override buttons created directly and give them a description as their data context
                    RedButton button = o as RedButton;

                    if( button != null )
                    {
                        button.DataContext = new ItemDescription.Button()
                        {
                            TextBox = _textBox
                        };
                    }
                }
            }
        }

        #endregion Event Handlers
    }

    namespace ItemDescription
    {
        /// <summary>
        /// Provides a standard way of creating uniform buttons as part of a <see cref="ButtonTextbox"/>
        /// </summary>
        public class Button : DependencyObject
        {
            #region Dependency Properties

            public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( "CommandParameter", typeof( object ), typeof( Button ) );

            #endregion Dependency Properties

            #region Internal Properties

            /// <summary>
            /// The textbox the button is associated with.
            /// </summary>
            /// <remarks>
            /// Used to make sure the button matches the textbox in style
            /// </remarks>
            internal TextBox TextBox { get; set; }

            #endregion Internal Properties

            #region Public Properties

            /// <summary>
            /// The size difference between the height of the associated textbox and the button
            /// </summary>
            public int CalculatedIconMargin
            {
                get
                {
                    if( TextBox != null )
                    {
                        return ( (int)TextBox.Height - IconSize ) / 2;
                    }

                    return 0;
                }
            }

            /// <summary>
            /// Width and Height of the internal <see cref="RedIcon"/>
            /// </summary>
            /// <remarks>
            /// Default value is 12
            /// </remarks>
            public int IconSize { get; set; } = 12;

            /// <summary>
            /// What's rendered on the <see cref="RedIcon"/>
            /// </summary>
            public Canvas Canvas { get; set; }

            /// <summary>
            /// Executed when the button is pressed
            /// </summary>
            public ICommand Command { get; set; }

            /// <summary>
            /// Parameter passed to the command when it's executed
            /// </summary>
            public object CommandParameter
            {
                get { return GetValue( CommandParameterProperty ); }
                set { SetValue( CommandParameterProperty, value ); }
            }

            #endregion Public Properties
        }
    }

    public class ButtonTextboxItemTemplateSelector : DataTemplateSelector
    {
        #region DataTemplateSelector Implementation

        public override DataTemplate SelectTemplate( object item, DependencyObject container )
        {
            FrameworkElement element = container as FrameworkElement;

            if ( element != null )
            {
                if ( item is ItemDescription.Button )
                {
                    return (DataTemplate)element.FindResource( "Button" );
                }
            }

            return null;
        }

        #endregion DataTemplateSelector Implementation
    }
}
